	package ar.edu.itba.it.cg.grupo01.impl.shape.shader;

import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.util.List;

import javax.vecmath.Point3f;
import javax.vecmath.Vector3f;

import ar.edu.itba.it.cg.grupo01.api.Intersection;
import ar.edu.itba.it.cg.grupo01.api.scene.Scene;
import ar.edu.itba.it.cg.grupo01.api.shape.Shape;
import ar.edu.itba.it.cg.grupo01.api.shape.light.Light;
import ar.edu.itba.it.cg.grupo01.api.texture.Texture;
import ar.edu.itba.it.cg.grupo01.api.texture.TextureFilter;
import ar.edu.itba.it.cg.grupo01.impl.RayImpl;
import ar.edu.itba.it.cg.grupo01.impl.RayTraceInformation;
import ar.edu.itba.it.cg.grupo01.impl.RayTracer;
import ar.edu.itba.it.cg.grupo01.impl.RayTracer.ColorHolder;
import ar.edu.itba.it.cg.grupo01.impl.color.Colors;
import ar.edu.itba.it.cg.grupo01.impl.scene.optimization.Octree;
import ar.edu.itba.it.cg.grupo01.impl.shape.Plane;
import ar.edu.itba.it.cg.grupo01.impl.shape.Triangle;
import ar.edu.itba.it.cg.grupo01.impl.texture.BilinearFilter;
import ar.edu.itba.it.cg.grupo01.impl.texture.TextureImpl;

public class DiffuseShader extends Shader {

	private Color diffColor;
	private Texture texture;

	public void setDiffColor(Color color) {
		this.diffColor = color;
	}

	public void setTexture(String texturePath) {
		try {
			TextureFilter filter = new BilinearFilter();
			texture = new TextureImpl(new File(texturePath), filter);
		} catch (IOException e) {
			throw new RuntimeException("Unable to load texture: " + texturePath);
		}
	}

	@Override
	public Color getShadeColor(Shape shape, Point3f intersectionPoint) {
		return getDiffColor(shape, intersectionPoint);
	}

	private Color getDiffColor(Shape shape, Point3f intersectionPoint) {

		if (texture == null) {
			return diffColor;
		}

		return texture.getColorAtPoint(shape
				.getUVCoordinates(intersectionPoint));
	}

	@Override
	public void shade(RayTraceInformation info) {
		RayTracer tracer = info.getTracer();
		Point3f intersectionPoint = info.getIntersectionPoint();
		Shape shape = info.getShape();
		Scene scene = info.getScene();
		ColorHolder color = info.getColor();
		Vector3f normal = info.getNormal();

		if (info.getIntersection().getType().equals(Intersection.Type.IN)) {
			normal.negate();
		}

		for (Light light : scene.getLights()) {

			List<Vector3f> dirs = light.getLigthDirs(intersectionPoint);
			float attenuation = light.getAttenuation(intersectionPoint);
			int hits = 0;

			Octree octree = info.getOctree();
			List<Plane> planes = scene.getPlanes();
			for (Vector3f lightDir : dirs) {
				if (tracer.hitsLight(shape, light, new RayImpl(
						intersectionPoint, lightDir), octree, planes)) {
					hits++;
				}
			}

			if (hits > 0) {
				float dot = dirs.get(0).dot(normal);

				if (shape instanceof Triangle && dot < 0) {
					dot = -dot;
				}

				if (dot > 0.0) {
					ColorHolder attenuatedLightColor = new ColorHolder(Colors
							.scale(light.getColor(), attenuation));

					if (hits != dirs.size()) {
						attenuatedLightColor.mul(hits);
						attenuatedLightColor.mul(1.0f / dirs.size());
					}

					Color diffuseColor = Colors
							.mulTo(getDiffColor(shape, intersectionPoint),
									attenuatedLightColor.getColor());

					color.madd(dot, diffuseColor);

				}
			}
		}
	}

}
